package cn.trasen.his.poc.std.core.action;

import cn.trasen.his.poc.std.api.emums.*;
import cn.trasen.his.poc.std.api.model.inpatient.InpatientRecord;
import cn.trasen.his.poc.std.api.model.inpatient.VisitRecord;
import cn.trasen.his.poc.std.api.model.major.BedOperationConfig;
import cn.trasen.his.poc.std.api.model.major.WardBed;
import cn.trasen.his.poc.std.api.pmodel.WardBedCardProxy;
import com.google.api.client.util.Maps;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.boot.base.model.ServerAction;
import pro.shushi.pamirs.boot.web.manager.MetaCacheManager;
import pro.shushi.pamirs.boot.web.manager.UiIoManager;
import pro.shushi.pamirs.boot.web.utils.PageLoadHelper;
import pro.shushi.pamirs.core.common.FetchUtil;
import pro.shushi.pamirs.framework.connectors.data.sql.Pops;
import pro.shushi.pamirs.meta.annotation.Action;
import pro.shushi.pamirs.meta.annotation.Function;
import pro.shushi.pamirs.meta.annotation.Model;
import pro.shushi.pamirs.meta.api.dto.condition.Pagination;
import pro.shushi.pamirs.meta.api.dto.wrapper.IWrapper;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
import pro.shushi.pamirs.meta.common.util.ListUtils;
import pro.shushi.pamirs.meta.constant.FunctionConstants;
import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum;
import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum;
import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum;
import pro.shushi.pamirs.meta.enmu.ViewTypeEnum;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
@Model.model(WardBedCardProxy.MODEL_MODEL)
public class BedCardProxyAction {

    @Resource
    private MetaCacheManager metaCacheManager;
    @Resource
    private UiIoManager uiIoManager;

    private String MAN_PERSON_LOGO = "http://39.103.145.77:9000/pamirs/upload/trasen/2024/12/18/男_1734496976993.svg";
    private String WOMAN_PERSON_LOGO = "http://39.103.145.77:9000/pamirs/upload/trasen/2024/12/18/女_1734497008127.svg";

    @Function.Advanced(type = FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryPage)
    @Function(openLevel = {FunctionOpenEnum.API})
    public Pagination<WardBedCardProxy> queryPage(Pagination<WardBedCardProxy> page, IWrapper<WardBedCardProxy> queryWrapper) {
        Pagination<WardBedCardProxy> pagination = new WardBedCardProxy().queryPage(page, queryWrapper);
        List<WardBedCardProxy> content = pagination.getContent();
        if (content.isEmpty()) {
            return pagination;
        }

        List<String> bedNos = ListUtils.transform(content, WardBedCardProxy::getBedNo);
        if (CollectionUtils.isEmpty(bedNos)) {
            return pagination;
        }
        // 根据床位号查询入院记录
        IWrapper<InpatientRecord> inpatientWrapper = Pops.<InpatientRecord>lambdaQuery()
                .from(InpatientRecord.MODEL_MODEL)
                .eq(InpatientRecord::getStatus, InpatientStatusEnum.SIGN_IN_AREA.getValue())
                .in(InpatientRecord::getBedNo, bedNos);
        List<InpatientRecord> inpatientRecords = new InpatientRecord().queryList(inpatientWrapper);
        if (CollectionUtils.isEmpty(inpatientRecords)) {
            return pagination;
        }

        // 将InpatientRecord按BedNo组织为Map
        Map<String, InpatientRecord> inpatientRecordMap = inpatientRecords.stream()
                .collect(Collectors.toMap(InpatientRecord::getBedNo, record -> record, (r1, r2) -> r1));
        // 批量查询VisitRecord数据
        List<Long> visitIds = ListUtils.transform(inpatientRecords, InpatientRecord::getVisitId);
        Map<Long, VisitRecord> visitRecordMap = Maps.newHashMap();
        if (CollectionUtils.isNotEmpty(visitIds)) {
            IWrapper<VisitRecord> visitWrapper = Pops.<VisitRecord>lambdaQuery()
                    .from(VisitRecord.MODEL_MODEL)
                    .in(VisitRecord::getId, visitIds);
            List<VisitRecord> visitRecords = new VisitRecord().queryList(visitWrapper);
            visitRecordMap = visitRecords.stream()
                    .collect(Collectors.toMap(VisitRecord::getId, record -> record, (r1, r2) -> r1));
        }

        for (WardBedCardProxy bedCardProxy : content) {
            InpatientRecord inpatientRecord = inpatientRecordMap.get(bedCardProxy.getBedNo());
            if (inpatientRecord != null) {
                VisitRecord visitRecord = visitRecordMap.get(inpatientRecord.getVisitId());
                // 处理单条数据
                handleOne(bedCardProxy, inpatientRecord, visitRecord);
            } else {
                handleNoVisit(bedCardProxy);
            }
        }

        // 填充操作元素
        fillOperateElement(content);

        return pagination;
    }

    @Function.Advanced(type = FunctionTypeEnum.QUERY)
    @Function.fun(FunctionConstants.queryByEntity)
    @Function(openLevel = {FunctionOpenEnum.API})
    public WardBedCardProxy queryOne(WardBedCardProxy query) {
        query = query.queryById();

        InpatientRecord inpatientRecord = new InpatientRecord().setBedNo(query.getBedNo()).setStatus(InpatientStatusEnum.SIGN_IN_AREA).queryOne();
        if (inpatientRecord == null) {
            return query;
        }
        VisitRecord visitRecord = new VisitRecord().setId(inpatientRecord.getVisitId()).queryById();
        // 处理单条数据
        if (visitRecord != null) {
            handleOne(query, inpatientRecord, visitRecord);
        } else {
            handleNoVisit(query);
        }

        return query;
    }

    @Action(displayName = "取消分床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy cancelBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「取消分床」成功");
        return data;
    }

    @Action(displayName = "转床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy transferBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「转床」成功");
        return data;
    }

    @Action(displayName = "包床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy reserveBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「包床」成功");
        return data;
    }

    @Action(displayName = "取消包床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy cancelReserveBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「取消包床」成功");
        return data;
    }

    @Action(displayName = "包房", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy reserveRoom(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「包房」成功");
        return data;
    }

    @Action(displayName = "取消包房", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy cancelReserveRoom(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「取消包房」成功");
        return data;
    }

    @Action(displayName = "占床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy occupyBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        data = data.queryById();
        if (data == null) {
            throw PamirsException.construct(PocDemoExpEnum.PARAMETER_ISNULL).errThrow();
        }
        // 其他状态的判断

        WardBed wardBed = new WardBed();
        wardBed.setId(data.getId());
        wardBed.setBedStatus(BedStatusEnum.OCCUPYBED);
        wardBed.updateById();
        PamirsSession.getMessageHub().info("操作「占床」成功");
        return data;
    }

    @Action(displayName = "取消占床", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy cancelOccupyBed(WardBedCardProxy data) {
        // TODO 具体逻辑
        WardBed wardBed = new WardBed();
        wardBed.setId(data.getId());
        wardBed.setBedStatus(BedStatusEnum.EMPTYBED);
        wardBed.updateById();
        PamirsSession.getMessageHub().info("操作「取消占床」成功");
        return data;
    }

    @Action(displayName = "分娩", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy deliverBaby(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「分娩」成功");
        return data;
    }

    @Action(displayName = "出院", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy dischargePatient(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「出院」成功");
        return data;
    }

    @Action(displayName = "转科", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy transferDepartment(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「转科」成功");
        return data;
    }

    @Action(displayName = "医嘱处理", bindingType = ViewTypeEnum.TABLE, contextType = ActionContextTypeEnum.SINGLE)
    public WardBedCardProxy processMedicalOrders(WardBedCardProxy data) {
        // TODO 具体逻辑
        PamirsSession.getMessageHub().info("操作「医嘱处理」成功");
        return data;
    }

    private void handleOne(WardBedCardProxy bedCardProxy, InpatientRecord inpatientRecord, VisitRecord visitRecord) {
        // 转换为天数
        long diffInMillis = new Date().getTime() - inpatientRecord.getInAreaDate().getTime();
        Long inDays = TimeUnit.MILLISECONDS.toDays(diffInMillis);
        bedCardProxy.setInDays(inDays);
        if (visitRecord != null) {
            bedCardProxy.setPatientName(visitRecord.getPatientName());
            bedCardProxy.setSex(visitRecord.getSex());
            bedCardProxy.setAge(visitRecord.getAge());
            bedCardProxy.setCurDiagnosisName(visitRecord.getCurDiagnosisName());
        }
        if (SexTypeEnum.ONE.equals(visitRecord.getSex())) {
            bedCardProxy.setPersonLogo(MAN_PERSON_LOGO);
        } else if (SexTypeEnum.TWO.equals(visitRecord.getSex())) {
            bedCardProxy.setPersonLogo(WOMAN_PERSON_LOGO);
        }

        bedCardProxy.setDeptName(inpatientRecord.getDeptName());
        bedCardProxy.setBedNo(inpatientRecord.getBedNo());
        bedCardProxy.setBedDocName(inpatientRecord.getBedDocName());
        bedCardProxy.setNurseName(inpatientRecord.getBedNurName());
        bedCardProxy.setVisitNo(inpatientRecord.getInpatientNo());
        bedCardProxy.setInAreaDate(inpatientRecord.getInAreaDate());
        bedCardProxy.setStatus(inpatientRecord.getStatus());
        bedCardProxy.setDanger(inpatientRecord.getDanger());
        bedCardProxy.setTendLevel(inpatientRecord.getTendLevel());
        bedCardProxy.setInpatientLabel(inpatientRecord.getInpatientLabel());

        if (bedCardProxy.getStatus() != null) {
            bedCardProxy.setStatusDisName(bedCardProxy.getStatus().getDisplayName());
        }
        if (bedCardProxy.getTendLevel() != null) {
            bedCardProxy.setTendLevelDisName(bedCardProxy.getTendLevel().getDisplayName());
        }
        if (bedCardProxy.getCardStatus() != null) {
            bedCardProxy.setCardStatusDisName(bedCardProxy.getCardStatus().getDisplayName());
        }
        if (CollectionUtils.isNotEmpty(bedCardProxy.getInpatientLabel())) {
            bedCardProxy.setInpatientLabelDisName(bedCardProxy.getInpatientLabel().stream().map(InpatientLabelEnum::getDisplayName).collect(Collectors.toList()));
        }

        // TODO:根据实际情况修改这里的逻辑
        if (inDays < 1 && inpatientRecord.getInHospitalStatus() == null) {
           if (PatBedCardStatusEnum.IN_HOSP.equals(inpatientRecord.getPatBedCardStatus())) {
               bedCardProxy.setInHospitalStatus(InHospitalStatusEnum.TODAY_IN);
           } else if (PatBedCardStatusEnum.OUT_HOSP.equals(inpatientRecord.getPatBedCardStatus())) {
               bedCardProxy.setInHospitalStatus(InHospitalStatusEnum.TODAY_OUT);
           } else if (PatBedCardStatusEnum.TRANSFER.equals(inpatientRecord.getPatBedCardStatus())) {
               bedCardProxy.setInHospitalStatus(InHospitalStatusEnum.TODAY_TRANS_IN);
           }
        } else {
            bedCardProxy.setInHospitalStatus(inpatientRecord.getInHospitalStatus());
        }
        bedCardProxy.setPatBedCardStatus(inpatientRecord.getPatBedCardStatus());

        // 床头卡显示需要（目前不知道具体数据从哪里来，先从住院记录中手动设置）
        // bedCardProxy.setCardStatus(inpatientRecord.getCardStatus());

        if (inpatientRecord.getInfantFlag() != null && StringUtils.equals(inpatientRecord.getInfantFlag().getValue(), "1")) {
            bedCardProxy.setPersonClass(PersonClassEnum.CHILD);
        } else {
            bedCardProxy.setPersonClass(PersonClassEnum.ADULT);
        }

        if (bedCardProxy.getInHospitalStatus() != null) {
            bedCardProxy.setInHospitalStatusDisName(bedCardProxy.getInHospitalStatus().getDisplayName());
        }
        if (bedCardProxy.getPersonClass() != null) {
            bedCardProxy.setPersonClassDisName(bedCardProxy.getPersonClass().getDisplayName());
        }
        if (bedCardProxy.getBedStatus() != null) {
            bedCardProxy.setBedStatusDisName(bedCardProxy.getBedStatus().getDisplayName());
        }
        if (bedCardProxy.getSex() != null) {
            bedCardProxy.setSexDisName(bedCardProxy.getSex().getDisplayName());
        }
        if (bedCardProxy.getPatBedCardStatus() != null) {
            bedCardProxy.setPatBedCardStatusDisName(bedCardProxy.getPatBedCardStatus().getDisplayName());
        }
    }

    private void fillOperateElement(List<WardBedCardProxy> content) {
        if (CollectionUtils.isEmpty(content)) {
            return;
        }
        List<BedOperationConfig> opConfigs = new BedOperationConfig().queryList();
        if (CollectionUtils.isEmpty(opConfigs)) {
            return;
        }

        Set<Long> saIds = new HashSet<>();
        for (BedOperationConfig operationConfig : opConfigs) {
            List<ServerAction> operateElement = operationConfig.getOperateElement();
            if (CollectionUtils.isEmpty(operateElement)) {
                continue;
            }
            saIds.addAll(ListUtils.transform(operateElement, ServerAction::getId));
        }

        List<ServerAction> dbServerActions = FetchUtil.fetchListByIds(ServerAction.class, saIds);
        Map<Long, ServerAction> saById = dbServerActions.stream()
                .collect(Collectors.toMap(ServerAction::getId, sa -> sa));
        for (BedOperationConfig operationConfig : opConfigs) {
            List<ServerAction> operateElement = operationConfig.getOperateElement();
            List<ServerAction> transOperateElement = new ArrayList<>();
            for (ServerAction sa: operateElement) {
                ServerAction dbServerAction = saById.get(sa.getId());
                pro.shushi.pamirs.boot.base.model.Action action = metaCacheManager.fetchAction(WardBedCardProxy.MODEL_MODEL, dbServerAction.getName());
                transOperateElement.add(PageLoadHelper.fillModuleAndModel(uiIoManager.cloneData((ServerAction) action)));
            }
            operationConfig.setOperateElement(transOperateElement);
        }

        Map<BedStatusEnum, BedOperationConfig> opConfigsMap = opConfigs.stream()
                    .collect(Collectors.toMap(BedOperationConfig::getBedStatus, user -> user));
        for (WardBedCardProxy wardBed : content) {
            BedOperationConfig operationConfig = opConfigsMap.get(wardBed.getBedStatus());
            if (operationConfig != null) {
                List<ServerAction> operateElement = operationConfig.getOperateElement();
                wardBed.setOperateElement(operateElement);
                wardBed.setOperateDisNames(ListUtils.transform(operateElement, ServerAction::getDisplayName));
            }
        }
    }

    private void handleNoVisit(WardBedCardProxy bedCardProxy) {
        bedCardProxy.setPersonClass(PersonClassEnum.NONE);
        bedCardProxy.setPersonClassDisName(PersonClassEnum.NONE.getDisplayName());
        bedCardProxy.setPatBedCardStatus(PatBedCardStatusEnum.NONE);
        bedCardProxy.setPatBedCardStatusDisName(PatBedCardStatusEnum.NONE.getDisplayName());
        if (bedCardProxy.getBedStatus() == null) {
            bedCardProxy.setBedStatus(BedStatusEnum.EMPTYBED);
            bedCardProxy.setBedStatusDisName(BedStatusEnum.EMPTYBED.getDisplayName());
        } else {
            bedCardProxy.setBedStatusDisName(bedCardProxy.getBedStatus().getDisplayName());
        }
    }

}
